工控網首頁
>

應用設計

>

ESM335x擴展總線中斷智能塊讀寫

ESM335x擴展總線中斷智能塊讀寫

1、綜述

ESM335x 嵌入式主板的提供帶中斷的精簡ISA擴展總線,主要用于支持高速數據采集、多路串口擴展以及其他的高級擴展應用。在這些應用中,往往出現需要按一定的順序讀寫一定量的數據的情況,如果用戶在應用程序中一次一次的調用讀寫操作將會很慢而且會占用較多系統資源。我們在Linux-4.1.6 ISA總線驅動增加了中斷時數據塊讀寫操作的功能,當有中斷發生時,驅動程序會按照用戶的設置讀寫塊數據,并將讀到的數據進行緩存,讀寫完之后驅動程序會通知應用程序,用戶在應用程序中通過讀操作就能獲得需要讀取的塊數據。使用驅動程序在中斷時自動讀寫能簡化用戶應用程序,減少塊讀寫操作的延遲。具體的使用方法在下面介紹。

2、數據結構及使用說明

使用發生中斷時驅動自動讀寫數據塊功能需要在應用程序中使用em335x_drivers.h頭文件,使能功能需要使用struct isa_transfer結構體,傳入此結構體數組給驅動以設置讀寫操作的參數:

struct isa_transfer

  {

     const void  *tx_buf;    /* 寫數據地址,不為NULL有效 */

      void        *rx_buf;    /* 讀數據地址,不為NULL有效 */

      unsigned    len;        /* 讀取長度 */

      unsigned    offset;   /* 總線地址 0x00 .. 0xFF */

      unsigned    inc;        /* 每次讀寫之后地址的增量 */

  };

  ● tx_buf: 不為NULL時, 表示寫操作

  ● rx_buf: 不為NULL時,表示讀操作,數據讀取存放地址

  ● tx_buf和rx_buf不能同時有效

  ● len:讀寫長度,以字節byte為單位,進行塊讀寫操作時必須為偶數,也可以進行單獨的1個byte的數據讀寫,即設置為1

  ● offset:讀寫操作地址,塊數據讀寫時offset必須為偶數

  ● inc:每次讀寫操作后地址增加量,1或者0

總線塊數據讀寫說明

ESM335x精簡ISA總線只有8位數據/地址線,但是硬件內部可以進行16bit的讀寫,并且會自動將16bit的數據分為低8位和高8位兩次讀寫,低8位和高8位處在連續的地址處(即必須有兩個相鄰的地址),我們在驅動中為了加快讀寫操作,在用戶進行塊讀寫(結構體中的len為偶數)時會使用16bit讀寫的方式,具體讀寫方式如下,請用戶注意讀寫地址的變化:

● 設置rx_buf有效,len=4, offset=0, inc=0時,驅動讀寫地址及順序為:

    低8位—offset,高8位—offset+1;低8位—offset,高8位—offset+1。

● 設置rx_buf有效,len=4, offset=0, inc=1時,驅動讀寫地址及順序為:

    低8位—offset,高8位—offset+1;低8位—offset+2,高8位—offset+3。

寫操作相同。

3、應用程序示例

使用ISA總線需要先打開相應的設備文件:

  int fd;

   fd = open("/dev/em335x_isa", O_RDWR);

   printf("open file = %d\n", fd);

   if(fd < 0)

   {

       return fd;    

   }

應用程序需要先初始化要傳遞給驅動的struct isa_transfer數組,讀寫順序和數組中的順序相同,用戶可自行設定,要使用中斷自動讀寫功能數組第一個元素必須初始化為0,否則將直接進行塊讀寫操作,而不使用中斷:

#define ARRAY_SIZE(a) (sizeof(a)) //用于計算數組字節數

      uint8_t tx[2] = { 0x5a, 0x55};  //第一次寫入數據

      uint8_t tx2[2] = { 0xaa, 0x1b}; //第二次寫入數據

      uint8_t rx[8];          //讀取數據存放處

      struct isa_transfer tr[4];

     

    //第一個元素必須設置為0才會使能中斷自動讀寫功能

        memset ( &tr[0], 0, sizeof(struct isa_transfer) );

     //第一次操作設置為寫

        tr[1].tx_buf = tx;

        tr[1].rx_buf = NULL;

        tr[1].len = ARRAY_SIZE(tx);

          tr[1].offset = 0;

          tr[1].inc = 1;

    //第二次操作設置為讀,應用程序中讀操作存放數據地址rx,總線起始地址為offset

         tr[2].tx_buf = NULL;

          tr[2].rx_buf = rx;

          tr[2].len = ARRAY_SIZE(rx) ;

          tr[2].offset = 4;

          tr[2].inc = 0;

    //第三次操作設置為寫

         tr[3].tx_buf = tx2;

          tr[3].rx_buf = NULL;

          tr[3].len = ARRAY_SIZE(tx2);

          tr[3].offset = 0;

          tr[3].inc = 1;

  調用ioctl函數傳遞數組地址,使能中斷塊讀寫操作:

  ret = ioctl(fd, ISA_IOC_MESSAGE(4), tr );

  設置過后的讀取地址必須保證在下次調用ioctl重新設置之前一直有效,用戶之后調用read函數時驅動程序會自動將數據寫入設置的讀取地址(示例中的rx數組),而與用戶在read函數中輸入的地址無關,這樣能夠簡化用戶應用程序中的設置,用戶只需要在每次read函數之后到ioctl傳遞的結構體數組中的讀地址處(rx數組)獲得數據,并在下次讀操作之前進行拷貝或者其他操作以防止數據丟失。

  停止中斷塊讀寫操作,只傳入一個全為0的struct isa_transfer機構體:

  ret = ioctl(fd, ISA_IOC_MESSAGE(1), &tr[0] );

  read函數讀取數據只需以sizeof(struct isa_transfer)為count參數,地址為無關參數,但是建議用戶傳入之前ioctl處的結構體數組地址,如下所示,之后數據便會讀到之前設置的結構體數組中指定的讀取數據存入地址處,即rx數組中:

  nNum = read(fd, tr, sizeof(struct isa_transfer));

  需要重新設置讀寫數據參數時需要重新設置結構體數組,并重新調用ioctl函數。

  設置完成后使用select函數查詢ISA總線狀態,如有中斷發生,并且驅動讀寫完了設置的數據塊,select函數將會返回大于0的數值,并且設置相應的讀文件標志,應用程序就可以調用read讀取數據了,select函數用法示例:

  //線程函數中調用select函數查詢總線狀態,如可讀,則調用read讀取數據到之前設置的地址

  int ISASelectThreadFunc(void* lparam)

  {

      int fd = * (int*)lparam;

      printf ( "fd %d\n", fd );

      fd_set fdRead;

      struct timeval aTime;

      int ret;

      while(1)

      {

          FD_ZERO(&fdRead);

          FD_SET(fd,&fdRead);

          aTime.tv_sec = 2;

          aTime.tv_usec = 0;

          ret = select ( fd+1, &fdRead, NULL, NULL, &aTime );

          if ( ret<0 )

              printf( "select, something wrong!\n " );

          if ( ret>0 )

          {

              if ( FD_ISSET(fd, &fdRead) )

              {

                  printf( "There is a IRQ!!! AND RW complete!\n" );

      /********************在此調用read************************/

                  read(fd, &tx[0], sizeof(struct isa_transfer));

                  //數據已經讀到rx數組中了,用戶可在此進行數據處理

              }

          }

          //判斷程序運行狀態,跳出循環

          //break;

      }

      pthread_exit( NULL );

      return 0;

  }

  //創建線程

  int StartPulseThread( int *fd  )

  {

      pthread_attr_t      attr;

      pthread_t           m_thread;

      int                 res;

 

      res = pthread_attr_init(&attr);

      if( res!=0 )

      {

          printf("Create attribute failed\n" );

      }

     res = pthread_attr_setscope( &attr, PTHREAD_SCOPE_SYSTEM );

      res += pthread_attr_setdetachstate( &attr, PTHREAD_CREATE_DETACHED );

      if( res!=0 )

      {

          printf( "Setting attribute failed\n" );

      }

      res = pthread_create( &m_thread, &attr, (void *(*)  (void*))&ISASelectThreadFunc, fd );

      if( res!=0 )

      {

          return -1;

      }

      pthread_attr_destroy( &attr );

     return 0;

  }

  關于ISA精簡總線的讀寫時序請參考《ESMARC 335x系列工控主板數據手冊》,單次讀寫周期190ns,使用中斷發生驅動程序自動塊讀寫功能時,最高寫速率為5MB/s,最高讀速率受硬件限制為3MB/s(兩次讀操作之間會有總線仲裁時間間隔),讀寫時序均與《ESMRC 335x 工控主板數據手冊》中的時序相同。我們將在后續工作中使用dma方式加快讀速度。

  如有疑問或需要使用此功能,請和我們聯系。

投訴建議

提交

查看更多評論
其他資訊

查看更多

Windows下STM32單片機eclipse編譯環境搭建

Android Studio應用開發簡介

WinCE工控主板WiFi解決方案

敬請關注成都英創微信公眾號

WinCE工控主板通過PPI協議連接西門子PLC